package cz.stv.pecinovsky.město;

import cz.stv.pecinovsky.správceplátna.IKreslený;
import cz.stv.pecinovsky.správceplátna.Kreslítko;
import cz.stv.pecinovsky.správceplátna.Obdélník;
import cz.stv.pecinovsky.správceplátna.SprávcePlátna;

import cz.stv.pecinovsky.utility.Barva;
import cz.stv.pecinovsky.utility.IO;
import cz.stv.pecinovsky.utility.Pozice;
import cz.stv.pecinovsky.utility.Rozměr;



/*******************************************************************************
 * Instance třídy {@code Město} je jedináček a představuje město,
 * do kterého budou postupně umísťovány různé objekty.
 * Město může být větší než aktuální plátno a umístí se vždy tak,
 * aby ve středu plátna bylo aktuální políčko, které lze nastavit.
 *
 * @author  Rudolf PECINOVSKÝ
 * @version 1.10.2678 — 2011-10-27
 */
public class Město implements IKreslený
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    /** Výchozí počet sloupců. */
    private static final int SLOUPCŮ_0 = 10;

    /** Výchozí počet řádků. */
    private static final int ŘÁDKŮ_0 = 10;

    /** Správce plátna, v němž se město vyskytuje. */
    private static final SprávcePlátna SP = SprávcePlátna.getInstance();

    /** Jediná přípustná instance města. */
    private static final Město jedináček = new Město(ŘÁDKŮ_0, SLOUPCŮ_0);



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================
//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================
    //== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================

    /** Aktuální velikost kroku správce plátna. */
    private int modul = SP.getKrok();

    /** Obdélník zobrazující plochu města. */
    private Obdélník podklad;

    /** Obdélník označující aktivní políčko. */
    private Obdélník aktivní;

    /** Aktuální počet sloupců města. */
    private int sloupců;

    /** Aktuální počet řádků města. */
    private int řádků;

    /** Sloupec políčka, které se bude zobrazovat. */
    private int aktSloupec;

    /** Řádek políčka, které se bude zobrazovat. */
    private int aktŘádek;



//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vrátí (jedinou existující) instanci města.
     *
     * @return Požadovaná instance
     */
    public static Město getInstance()
    {
        return jedináček;
    }


    /***************************************************************************
     * Vytvoří nové město se zadaným počtem sloupců a řádků.
     * Prozatím se nepočítá, že by se rozměr města v průběhu jeho života měnil.
     *
     * @param sloupců   Počet sloupců vytvářeného města
     * @param řádků     Počet řádků vytvářeného města
     */
    private Město(int sloupců, int řádků)
    {
        this.sloupců = sloupců;
        this.řádků   = řádků;

        aktSloupec = this.sloupců / 2;
        aktŘádek   = this.řádků / 2;

        podklad = new Obdélník(0, 0, 1, 1, Barva.KOUŘOVÁ);
        aktivní = new Obdélník(0, 0, 1, 1, Barva.MLÉČNÁ);

        SP.přidej(this);
    }



//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

    /***************************************************************************
     * Vrátí velikost modulu, tj. délku strany políčka města.
     *
     * @return Velikost modulu
     */
    public int getModul()
    {
        return modul;
    }


    /***************************************************************************
     * Vrátí aktuální políčkový rozměr města, tj. počet jeho sloupců a řádků.
     *
     * @return Aktuální políčkový rozměr města
     */
    public Rozměr getPRozměr()
    {
        return new Rozměr(sloupců, řádků);
    }



//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Přestěhuje aktivní pole do jiné pozice města
     * a tím automaticky přesune město na plátně tak,
     * aby bylo aktivní pole opět uprostřed plátna.
     * Není-li nastavovaná pozice uvnitř města, vyhodí výjimku.
     *
     * @param sloupec Nový sloupec aktivního pole
     * @param řádek   Nový řádek aktivního pole
     */
    public void aktivníNa(int sloupec, int řádek)
    {
        if ((sloupec < 0)  ||  (this.sloupců <= sloupec)  ||
            (řádek   < 0)  ||  (this.řádků   <= řádek)    )
        {
            throw new IllegalArgumentException( "Pozice mimo hranice města." +
                "\nSouřadnice musí být >=0, sloupec<" + sloupců +
                ", řádek<" +  řádků +
                "\nByl však zadán sloupec=" + sloupec + ", řádek=" + řádek);
        }
        aktSloupec = sloupec;
        aktŘádek   = řádek;
        SP.překresli();
    }


    /***************************************************************************
     * Prostřednictvím dodaného kreslítka vykreslí obraz své instance.
     *
     * @param kreslítko Kreslítko, které nakreslí instanci
     */
    @Override
    public void nakresli(Kreslítko kreslítko)
    {
        modul = SP.getKrok();
        int sloupcůPlátna = SP.getSloupců();
        int řádkůPlátna   = SP.getŘádků();

        //Aktuální políčko města musí být uprostřed plátna
        int apSloupec = sloupcůPlátna / 2;
        int apŘádek   = řádkůPlátna   / 2;

        //Pozice podkladu města se musí nastavit tak,
        //aby aktuální políčko bylo na plátně ve spočtené pozici
        int xMěsta = (apSloupec - aktSloupec) * modul;
        int yMěsta = (apŘádek   - aktŘádek  ) * modul;
        podklad.setPozice(xMěsta, yMěsta);
        podklad.setRozměr(sloupců*modul, řádků*modul);

        podklad.nakresli(kreslítko);

        aktivní.setPozice((2*apSloupec - 1) * modul / 2,
                          (2*apŘádek   - 1) * modul / 2);
        aktivní.setRozměr (2*modul);
        aktivní.nakresli(kreslítko);
    }


            /***************************************************************************
             *
             */
            public void přidejVozidlo()
            {

            }



    /***************************************************************************
     * Přidá do města zadaný okruha na zadanou políčkovou pozici
     * a pokud se okruh do města nevejde, zvětší velikost města.
     * Kříží-li se přidávaný okruh s nějakým již existujícím okruhem,
     * umístí na danou křižovatku semafor.
     *
     * @param okruh   Přidávaný okruh
     * @param pPozice Políčková pozice přidávaného okruhu
     */
    public void přidejOkruh(Okruh okruh, Pozice pPozice)
    {

    }


    /***************************************************************************
     * Vrací textovou reprezentaci (podpis) dané instance
     * používanou především k ladicím účelům.
     *
     * @return Požadovaná textová reprezentace
     */
    @Override
    public String toString()
    {
        return "Město_(" + new Rozměr(sloupců, řádků) + 
               ", aktivní-" + new Pozice(aktSloupec, aktŘádek) + ")";
    }


    
//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTY A METODA MAIN =======================================================
//
//    /***************************************************************************
//     * Testovací metoda.
//     */
//    public static void test()
//    {
//        Město inst = new Město();
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main( String[] args )  {  test();  }
}

